/***************************************************************************
 *   Copyleft 2006-2007 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#include "./Object3D.h"
#include "../../MemTracer/MemoryTracker.h"

cInt Object3D::mCnt = -2;
/**************************************************************
* Constructors                                                *
***************************************************************/
Object3D::Object3D(): mNrOfEdges(0), mNrOfVertices(0), 
					mVertexTable(cNull), mEdgeTable(cNull) {
	mID = Object3D::mCnt++;
	mColor = Color::ToWinColor(RED);
	mVisible = true;
}

Object3D::Object3D(cInt iVertices, cInt iEdges) {
	if (iVertices > 0 && iEdges > 0) {
		mNrOfVertices = iVertices;
		mNrOfEdges = iEdges;
		mVertexTable = new Point4D[mNrOfVertices];
		mEdgeTable = new EdgePointer[mNrOfEdges];
	}
	mID = Object3D::mCnt++;
	mVisible = true;
}

Object3D::~Object3D() {
	if (mVertexTable) {
		delete [] mVertexTable;
		mVertexTable = cNull;
	}
	if (mEdgeTable) {
		delete [] mEdgeTable;
		mEdgeTable = cNull;
	}
	mNrOfEdges = 0;
	mNrOfVertices = 0;
	//mID = Object3D::mCnt--;
}

/**************************************************************
* Other helpful functions                                     *
***************************************************************/
cVoid Object3D::Render(Renderer& renderer, Matrix4D& matrix, ProjectionPlane& plane) {
	Point4D a, b;
	cInt iHalfWidth = renderer.GetWidth() >> 1, iHalfHeight = renderer.GetHeight() >> 1;
	Matrix4D mTempMatrix = matrix * mMatrix * mObjectMatrix;
	if (mVisible) {
		if (mVertexTable && mEdgeTable) {
			for (cInt i = 0; i < mNrOfEdges; i++) {
				a = mVertexTable[mEdgeTable[i].mBegin];
				b = mVertexTable[mEdgeTable[i].mEnd];
				a = mTempMatrix * a;
				b = mTempMatrix * b;
				if (!Clip(a, b, plane)) {
					continue;
				}
				a.Normalize();
				b.Normalize();
				a.mX += iHalfWidth;
				a.mY = -a.mY + iHalfHeight;
				b.mX += iHalfWidth;
				b.mY = -b.mY + iHalfHeight;

				renderer.DrawLine(a, b, mColor);
			}
		}
	}
}

cVoid Object3D::Render(Renderer& renderer, Matrix4D& matrix, ProjectionPlane& plane, cWinColor color) {
	Point4D a, b;
	
	if (mVisible) {
		if (mVertexTable && mEdgeTable) {
			for (cInt i = 0; i < mNrOfEdges; i++) {
				a = mVertexTable[mEdgeTable[i].mBegin];
				b = mVertexTable[mEdgeTable[i].mEnd];
				a = matrix * mMatrix * mObjectMatrix * a;
				b = matrix * mMatrix * mObjectMatrix * b;
				if (!Clip(a, b, plane)) {
					continue;
				}
				a.Normalize();
				b.Normalize();
				a.mX += (renderer.GetWidth() >> 1);
				a.mY = -a.mY + (renderer.GetHeight() >> 1);
				b.mX += (renderer.GetWidth() >> 1);
				b.mY = -b.mY + (renderer.GetHeight() >> 1);

				renderer.DrawROPLine(a, b, color);
			}
		}
	}
}

cBool Object3D::Clip(Point4D &a, Point4D &b, ProjectionPlane& plane) {
	cFloat fClipDistance = plane.GetNearClippingPlane();

	if (a.mW < fClipDistance && b.mW < fClipDistance) {
		return false;
	}

	if (a.mW > b.mW) {
		Point4D temp = a;
		a = b;
		b = temp;
	}
	if (a.mW < fClipDistance) {
		a = b + (a - b) * ((fClipDistance - b.mW) / (a.mW - b.mW));
	}

	return true;
}

cVoid Object3D::Update(cInt iVertices, cInt iEdges) {
	if (mVertexTable) {
		delete [] mVertexTable;
		mVertexTable = cNull;
	}
	if (mEdgeTable) {
		delete [] mEdgeTable;
		mEdgeTable = cNull;
	}
	mNrOfEdges = iEdges;
	mNrOfVertices = iVertices;
	mVertexTable = new Point4D[mNrOfVertices];
	mEdgeTable = new EdgePointer[mNrOfEdges];
}

/*virtual*/ cVoid Object3D::Transform(Matrix4D& matrix) {
	mObjectMatrix = matrix * mObjectMatrix;
}

/*virtual*/ cVoid Object3D::Transform(Matrix4D& matrix, cBool bRemember) {
	if (!bRemember) {
		mMatrix = matrix * mMatrix;
	} else {
		mObjectMatrix = matrix * mObjectMatrix;
	}
}


Matrix4D Object3D::GetTransformationMatrix() {
	return mMatrix;
}

cInt Object3D::GetID() {
	return mID;
}

cVoid Object3D::SetVisible() {
	mVisible = !mVisible;
}

cBool Object3D::GetVisible() {
	return mVisible;
}

cInt Object3D::NrOfAllCreatedObjects() {
	return Object3D::mCnt;
}